__author__ = 'cain76'

import os
import sys
import random

sys.path.insert(0, os.path.expanduser('~') + '/lib/python')

from mylib.gl3d.drawobject import *


class GameCell(object):
    tex = {}
    GC_WALL = 11
    GC_TYPE0 = 20
    GC_TYPE1 = 21
    GC_TYPE2 = 22
    GC_TYPE3 = 23
    GC_TYPE4 = 24
    GC_TYPE5 = 25
    GC_TYPE6 = 26
    GC_TYPE7 = 27
    GC_COUNT = 8
    use_multi_tex = 0

    def __init__(self, cell_type=0):
        self.tex_index = 0
        self.tex_count = 0
        self.animate = 0.0
        self.pos = Vec3(0, 0, 0)
        self.dst = Vec3(0, 0, 0)
        self.rot = Vec3(0, 0, 0)
        self.dir = Vec3(0, 0, 0)
        self.gra = Vec3(0, 0, 0)
        self.type = cell_type

    @staticmethod
    def set_texture(gct, tid, idx=0):
        """
        gct : GameCell Type
        tid : Texture ID
        idx : index
        GameCell.use_multi_tex
        """
        if gct not in GameCell.tex.keys():
            GameCell.tex[gct] = {}
        GameCell.tex[gct][idx] = tid


class GameItem(object):
    MOVE_SPEED = 1.5
    MOVE_END_X = 1
    MOVE_END_Y = 2
    MOVE_END_Z = 4
    MOVE_END_ALL = 7
    ROTATE_SPEED = 360.0
    ROTATE_END_X = 8
    ROTATE_END_Y = 16
    ROTATE_END_Z = 32
    ROTATE_END_ALL = 56

    NEXT = []
    MAX_NEXT = 5

    def __init__(self):
        self.vertex_list = []
        self.do = DrawObject()
        self.gc = []
        self.type = 0
        self.cell_count = 0
        self.pos = Vec3(0, 0, 0)
        self.dst = Vec3(0, 0, 0)
        self.rot = Vec3(0, 0, 0)

    @staticmethod
    def set_texture(gct, tid, idx=0):
        """
        gct : GameCell Type
        tid : Texture ID
        idx : index
        """
        if gct not in GameCell.tex.keys():
            GameCell.tex[gct] = {}
        GameCell.tex[gct][idx] = tid

    def get_cell_positions(self):
        vl = []
        for v in self.vertex_list:
            vl.append(Vec3(self.dst.x + v.x, self.dst.y, self.dst.z + v.y))
        return vl

    def set_pos(self, _x=0.0, _y=0.0, _z=0.0):
        self.pos = Vec3(_x, _y, _z)

    def set_dst(self, _x=0.0, _y=0.0, _z=0.0):
        self.dst = Vec3(_x, _y, _z)

    def move(self, _x=0.0, _y=0.0, _z=0.0):
        self.set_dst(self.dst.x + _x, self.dst.y + _y, self.dst.z + _z)

    def update_move(self, ms):
        dist = self.pos.get_distance(self.dst)
        if dist < 1.1: dist = 1.0
        else: dist *= 2.0
        _s = ms * GameItem.MOVE_SPEED * dist
        ends = 0

        if self.pos == self.dst: return GameItem.MOVE_END_ALL

        if self.pos.x < self.dst.x:
            self.pos.x += _s
            if self.pos.x > self.dst.x:
                self.pos.x = self.dst.x
                ends |= GameItem.MOVE_END_X
        elif self.pos.x > self.dst.x:
            self.pos.x -= _s
            if self.pos.x < self.dst.x:
                self.pos.x = self.dst.x
                ends |= GameItem.MOVE_END_X

        if self.pos.y < self.dst.y:
            self.pos.y += _s
            if self.pos.y > self.dst.y:
                self.pos.y = self.dst.y
                ends |= GameItem.MOVE_END_Y
        elif self.pos.y > self.dst.y:
            self.pos.y -= _s
            if self.pos.y < self.dst.y:
                self.pos.y = self.dst.y
                ends |= GameItem.MOVE_END_Y

        if self.pos.z < self.dst.z:
            self.pos.z += _s
            if self.pos.z > self.dst.z:
                self.pos.z = self.dst.z
                ends |= GameItem.MOVE_END_Z
        elif self.pos.z > self.dst.z:
            self.pos.z -= _s
            if self.pos.z < self.dst.z:
                self.pos.z = self.dst.z
                ends |= GameItem.MOVE_END_Z

        return ends

    def update_rotate(self, ms):
        _s = ms * GameItem.ROTATE_SPEED
        ends = 0

        if self.rot == Vec3(0.0, 0.0, 0.0): return GameItem.ROTATE_END_ALL

        if self.rot.x < 0.0:
            self.rot.x += _s
            if self.rot.x > 0.0:
                self.rot.x = 0.0
                ends |= GameItem.ROTATE_END_X
        elif self.rot.x > 0.0:
            self.rot.x -= _s
            if self.rot.x < 0.0:
                self.rot.x = 0.0
                ends |= GameItem.ROTATE_END_X

        if self.rot.y < 0.0:
            self.rot.y += _s
            if self.rot.y > 0.0:
                self.rot.y = 0.0
                ends |= GameItem.ROTATE_END_Y
        elif self.rot.y > 0.0:
            self.rot.y -= _s
            if self.rot.y < 0.0:
                self.rot.y = 0.0
                ends |= GameItem.ROTATE_END_Y

        if self.rot.z < 0.0:
            self.rot.z += _s
            if self.rot.z > 0.0:
                self.rot.z = 0.0
                ends |= GameItem.ROTATE_END_Z
        elif self.rot.z > 0.0:
            self.rot.z -= _s
            if self.rot.z < 0.0:
                self.rot.z = 0.0
                ends |= GameItem.ROTATE_END_Z

        return ends

    def update_animate(self, ms):
        idx = 0
        for v in self.vertex_list:
            gc = self.gc[idx]
            try:
                if gc.type > 0:
                    tex_cnt = len(GameCell.tex[gc.type].keys())
                    gc.animate += ms
                    if gc.animate > 1.0:
                        gc.tex_index += 1
                        gc.animate -= 1.0
                    _, gc.tex_index = divmod(gc.tex_index, tex_cnt)
                    _, gc.rot.x = divmod(gc.rot.x + ms * 50.0, 360)
                    _, gc.rot.y = divmod(gc.rot.y + ms * 50.0, 360)
                    _, gc.rot.z = divmod(gc.rot.z + ms * 50.0, 360)
            except KeyError:
                pass
            idx += 1

    def update(self, ms):
        self.update_animate(ms)
        endm = self.update_move(ms)
        endr = self.update_rotate(ms)
        return endm | endr

    def render_next(self, shader, xx, yy, zz):
        glTranslatef(xx, yy, zz)
        for i in range(self.MAX_NEXT):
            glTranslatef(0.0 - i, 0.0 - 0.5 * i, 0.0)
            self.NEXT[i].render(shader)
            glTranslatef(0.0 + i, 0.0 + 0.5 * i, 0.0)
        # self.NEXT[1].render(shader)
        glTranslatef(-xx, -yy, -zz)

    def render(self, shader):
        idx = 0
        glTranslatef(self.pos.x, self.pos.y, self.pos.z)

        glRotatef(self.rot.x, 1.0, 0.0, 0.0)
        glRotatef(self.rot.y, 0.0, 1.0, 0.0)
        glRotatef(self.rot.z, 0.0, 0.0, 1.0)

        for v in self.vertex_list:
            gc = self.gc[idx]
            if gc.type > 0:
                if gc.type in GameCell.tex.keys():
                    try:
                        glEnable(GL_TEXTURE_2D)
                        tid, alpha = GameCell.tex[gc.type][gc.tex_index]
                        if shader is not None: shader.pass_texture(tid)
                        if GameCell.use_multi_tex > 1:
                            tid2, _ = GameCell.tex[1][0]
                            if shader is not None: shader.pass_texture(tid2, number=2)
                            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)
                            '''
                            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE)
                            glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0)
                            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR)
                            glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1)
                            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR)
                            '''
                            glActiveTexture(GL_TEXTURE0)
                            glBindTexture(GL_TEXTURE_2D, tid2)
                            glActiveTexture(GL_TEXTURE1)

                        if alpha: glEnable(GL_BLEND)
                        else: glDisable(GL_BLEND)
                        glBindTexture(GL_TEXTURE_2D, tid)
                    except KeyError:
                        continue
                else:
                    glDisable(GL_TEXTURE_2D)
                    glColor4fv(RGBA.Colors[gc.type])
                if gc.type < 20:
                    if GameCell.use_multi_tex > 1:
                        self.do.glDrawCubeMT(v.x, 0, v.y, 0.45, rotate_x=gc.rot.x, rotate_y=gc.rot.y, rotate_z=gc.rot.z)
                    else:
                        self.do.glDrawCube(v.x, 0, v.y, 0.45, rotate_x=gc.rot.x, rotate_y=gc.rot.y, rotate_z=gc.rot.z)
                else:
                    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
                    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
                    self.do.gluDrawSphere(v.x, 0, v.y, 0.45, slices=16, stacks=16, rotate_x=gc.rot.x, rotate_y=gc.rot.y,
                                          rotate_z=gc.rot.z)

            idx += 1
        glRotatef(-self.rot.z, 0.0, 0.0, 1.0)
        glRotatef(-self.rot.y, 0.0, 1.0, 0.0)
        glRotatef(-self.rot.x, 1.0, 0.0, 0.0)
        glTranslatef(-self.pos.x, -self.pos.y, -self.pos.z)


class TetrisItem(GameItem):
    def __init__(self, t1=None):
        GameItem.__init__(self)
        self.index = 0
        self.cell_count = 4
        if t1 is not None:
            self.set_type(t1, 0)

    @staticmethod
    def get_type_vertex_list(i, n):
        if i == 0:  # I
            if n == 0: return [Vec3(0, 0), Vec3(-2, 0), Vec3(-1, 0), Vec3(1, 0)]
            elif n == 1: return [Vec3(0, 0), Vec3(0, -2), Vec3(0, -1), Vec3(0, 1)]
            elif n == 2: return [Vec3(0, 0), Vec3(2, 0), Vec3(1, 0), Vec3(-1, 0)]
            elif n == 3: return [Vec3(0, 0), Vec3(0, 2), Vec3(0, 1), Vec3(0, -1)]
        elif i == 1:  # O
            if n == 0: return [Vec3(0, 0), Vec3(-1, 0), Vec3(-1, -1), Vec3(0, -1)]
            elif n == 1: return [Vec3(0, 0), Vec3(-1, 0), Vec3(-1, -1), Vec3(0, -1)]
            elif n == 2: return [Vec3(0, 0), Vec3(-1, 0), Vec3(-1, -1), Vec3(0, -1)]
            elif n == 3: return [Vec3(0, 0), Vec3(-1, 0), Vec3(-1, -1), Vec3(0, -1)]
        elif i == 2:  # T
            if n == 0: return [Vec3(0, 0), Vec3(-1, 0), Vec3(0, -1), Vec3(1, 0)]
            elif n == 1: return [Vec3(0, 0), Vec3(0, -1), Vec3(1, 0), Vec3(0, 1)]
            elif n == 2: return [Vec3(0, 0), Vec3(1, 0), Vec3(0, 1), Vec3(-1, 0)]
            elif n == 3: return [Vec3(0, 0), Vec3(0, 1), Vec3(-1, 0), Vec3(0, -1)]
        elif i == 3:  # L                                                            ##########################
            if n == 0: return [Vec3(0, 0), Vec3(-1, 0), Vec3(1, 0), Vec3(1, -1)]  # #######O##O########OO####
            elif n == 1: return [Vec3(0, 0), Vec3(0, -1), Vec3(0, 1), Vec3(1, 1)]  # ####OXO##X###OXO###X####
            elif n == 2: return [Vec3(0, 0), Vec3(1, 0), Vec3(-1, 0), Vec3(-1, 1)]  # ########OO##O#####O####
            elif n == 3: return [Vec3(0, 0), Vec3(0, 1), Vec3(0, -1), Vec3(-1, -1)]  # ######################
        elif i == 4:  # J
            if n == 0: return [Vec3(0, 0), Vec3(-1, 0), Vec3(1, 0), Vec3(-1, -1)]  # ####O####OO########O####
            elif n == 1: return [Vec3(0, 0), Vec3(0, -1), Vec3(0, 1), Vec3(1, -1)]  # ###OXO##X###OXO###X####
            elif n == 2: return [Vec3(0, 0), Vec3(1, 0), Vec3(-1, 0), Vec3(1, 1)]  # #########O#####O##OO####
            elif n == 3: return [Vec3(0, 0), Vec3(0, 1), Vec3(0, -1), Vec3(-1, 1)]  # #######################
        elif i == 5:  # Z
            if n == 0: return [Vec3(0, 0), Vec3(-1, -1), Vec3(0, -1), Vec3(1, 0)]  # ########################
            elif n == 1: return [Vec3(0, 0), Vec3(1, -1), Vec3(1, 0), Vec3(0, 1)]  # #####OO#######O#########
            elif n == 2: return [Vec3(0, 0), Vec3(-1, -1), Vec3(0, -1), Vec3(1, 0)]  # ####XO#####XO#########
            elif n == 3: return [Vec3(0, 0), Vec3(1, -1), Vec3(1, 0), Vec3(0, 1)]  # #############O##########
        elif i == 6:  # S
            if n == 0: return [Vec3(0, 0), Vec3(-1, 0), Vec3(0, -1), Vec3(1, -1)]  # ########################
            elif n == 1: return [Vec3(0, 0), Vec3(0, 1), Vec3(-1, 0), Vec3(-1, -1)]  # ######OO####O#########
            elif n == 2: return [Vec3(0, 0), Vec3(-1, 0), Vec3(0, -1), Vec3(1, -1)]  # #####OX#####OX########
            elif n == 3: return [Vec3(0, 0), Vec3(0, 1), Vec3(-1, 0), Vec3(-1, -1)]  # #############O########
        return []

    def set_type(self, t, i):
        self.vertex_list = self.get_type_vertex_list(t, i)
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t))
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t))
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t))
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t))
        self.type = t
        self.index = i

    def get_next(self):
        while len(self.NEXT) < self.MAX_NEXT + 1:
            self.NEXT.append(TetrisItem(random.randint(0, 6)))
        n = self.NEXT.pop(0)
        return n

    def rotate(self, _r=1):
        self.rot.y += _r * 90
        _, i = divmod(self.index + self.cell_count + _r, self.cell_count)
        self.vertex_list = self.get_type_vertex_list(self.type, i)
        self.index = i


class HexaItem(GameItem):
    def __init__(self, t1=None, t2=None, t3=None):
        GameItem.__init__(self)
        self.index = 0
        self.cell_count = 3
        if None not in (t1, t2, t3):
            self.set_type(t1, t2, t3, 0)

    @staticmethod
    def get_type_vertex_list(n):
        if n == 0: return [Vec3(0, 0), Vec3(0, 1), Vec3(0, 2)]
        elif n == 1: return [Vec3(0, 1), Vec3(0, 2), Vec3(0, 0)]
        elif n == 2: return [Vec3(0, 2), Vec3(0, 0), Vec3(0, 1)]
        else: return []

    def set_type(self, t1, t2, t3, i):
        self.vertex_list = self.get_type_vertex_list(i)
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t1))
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t2))
        self.gc.append(GameCell(GameCell.GC_TYPE0 + t3))
        self.type = t1
        self.index = i

    def get_next(self):
        while len(self.NEXT) < self.MAX_NEXT + 1:
            self.NEXT.append(HexaItem(random.randint(1, 6), random.randint(1, 6), random.randint(1, 6)))
        n = self.NEXT.pop(0)
        return n

    def rotate(self, _r=1):
        # self.rot.y += _r * 90
        _, i = divmod(self.index + self.cell_count + _r, self.cell_count)
        self.vertex_list = self.get_type_vertex_list(i)
        self.index = i


class PuyoItem(GameItem):
    def __init__(self):
        GameItem.__init__(self)
        pass


class ExplosionCells:
    def __init__(self):
        self.list = []
        self.do = DrawObject()

    def add(self, gc, _x, _y):
        for i in (-0.1, -0.2, -0.3, 0.3, 0.2, 0.1):
            ec = GameCell(gc.type)
            ec.tex_index = gc.tex_index
            ec.pos = Vec3(_x, 1.0, _y)
            ec.dst = Vec3(i, 0.1, 2)
            ec.dir = Vec3(0.0, 1.0, 1.0)
            ec.gra = Vec3(0.0, -0.98, -0.98)
            ec.rot = Vec3(random.randrange(1, 50), random.randrange(1, 50), random.randrange(1, 50))
            ec.animate = 0.98
            self.list.append(ec)

    def update(self, ms):
        for e in self.list:
            e.dst.z -= e.animate * ms
            e.pos.x += (e.dst.x * ms)
            e.pos.y += (e.dst.y * ms)
            e.pos.z += (e.dst.z * ms)
            e.rot += (random.randrange(5, 15))
            if e.pos.z < -20.0: self.list.remove(e)

    def render(self, Shader):
        for e in self.list:
            try:
                tid, alpha = GameCell.tex[e.type][e.tex_index]
                if alpha: glEnable(GL_BLEND)
                else: glDisable(GL_BLEND)
                glBindTexture(GL_TEXTURE_2D, tid)
                if Shader is not None: Shader.pass_texture(tid)
            except KeyError:
                continue
            self.do.glDrawTri(e.pos.x, e.pos.y, e.pos.z, size=0.45, rotate_x=e.rot.x, rotate_y=e.rot.y,
                              rotate_z=e.rot.z)

            # self.do.glDrawQuad(e.pos.x, e.pos.y, e.pos.z, ('xz', 0.45, 0.45),
            # rotate_x=e.rot.x, rotate_y=e.rot.y, rotate_z=e.rot.z)


class GameMap(object):
    GT_TETRIS = 1
    GT_HEXA = 2
    GT_MATCH = 3
    GT_PUYO = 4
    GT_SAME = 5
    SCORE_MULTI = [1.2, 4.0, 4.0, 3.0, 1.0]

    def __init__(self, width=None, height=None, game_type=GT_TETRIS):
        if game_type == self.GT_TETRIS:
            w = 12
            h = 21
        elif game_type == self.GT_HEXA:
            w = 8
            h = 18
        elif game_type == self.GT_PUYO:
            w = 9
            h = 20
        elif game_type == self.GT_SAME:
            w = 22
            h = 22
        else:  # elif game_type == self.GT_MATCH:
            w = 11
            h = 11
        self.game_type = game_type
        if width is None: self.width = w
        else: self.width = width
        if height is None: self.height = h
        else: self.height = height

        self.ec = ExplosionCells()
        self.do = DrawObject()

        self.data = []
        for _y in range(self.height):
            for _x in range(self.width):
                if _y == 0: gc = GameCell(GameCell.GC_WALL)
                elif _x in (0, self.width - 1): gc = GameCell(GameCell.GC_WALL)
                else:
                    if game_type != self.GT_MATCH:
                        gc = GameCell(0)
                    else:
                        gc = GameCell(random.randint(GameCell.GC_TYPE0, GameCell.GC_TYPE7))

                self.data.append(gc)

    def get_type(self): return self.game_type

    def get_type_multi(self): return self.SCORE_MULTI[self.game_type - 1]

    def get_top(self): return self.height - 1

    def get_width(self): return self.width

    def get_centeri(self): return self.width // 2, self.height // 2

    def get_centerf(self): return self.width / 2.0, self.height / 2.0

    def set_texture(self, gct, tid, idx=0):
        """
        gct : GameCell Type
        tid : Texture ID
        idx : index
        """
        if gct not in GameCell.tex.keys():
            GameCell.tex[gct] = {}
        GameCell.tex[gct][idx] = tid

    def _idx(self, x, y): return x + y * self.width

    def check_collide(self, vl):
        for v in vl:
            try:
                if self.data[self._idx(v.x, v.z)].type > 0: return False
            except IndexError:
                continue
        return True

    def set_item(self, item):
        vl = item.get_cell_positions()
        idx = 0
        for v in vl:
            p = self._idx(v.x, v.z)
            self.data[p] = item.gc[idx]
            idx += 1

    '''
    def _delete_line(self, checks, sy):
        x = 1
        while x < self.width - 1:
            y = sy
            self.ec.add(self.data[self._idx(x, y)], x, y)
            while y < self.height - 1:
                self.data[self._idx(x, y)] = self.data[self._idx(x, y + 1)]
                y += 1
            self.data[self._idx(x, self.height - 1)] = GameCell(0)
            x += 1
    '''

    def scroll_down(self, x, y):
        while y < self.height - 1:
            self.data[self._idx(x, y)] = self.data[self._idx(x, y + 1)]
            y += 1
        if self.game_type != self.GT_MATCH:
            self.data[self._idx(x, self.height - 1)] = GameCell(0)
        else:
            self.data[self._idx(x, self.height - 1)] = GameCell(random.randint(GameCell.GC_TYPE0, GameCell.GC_TYPE7))

    def _delete_checks(self, checks):
        dels = 0
        x = 1
        while x < self.width - 1:
            y = self.height - 1
            while y > 0:
                if checks[self._idx(x, y)] > 0:
                    self.ec.add(self.data[self._idx(x, y)], x, y)
                    self.scroll_down(x, y)
                    dels += 1
                y -= 1
            x += 1
        return dels

    def _check_line(self, checks, y):
        x = 1
        while x < self.width - 1:
            if self.data[self._idx(x, y)].type < 10: return checks[:], False
            x += 1
        x = 1
        while x < self.width - 1:
            checks[self._idx(x, y)] = 1
            x += 1
        return checks[:], True

    def _check_match3(self, checks, x_, y_):
        is_del = False
        d00 = self.data[self._idx(x_, y_)]
        if d00.type < 1: return checks[:], is_del

        if d00.type == self.data[self._idx(x_ - 1, y_)].type and d00.type == self.data[self._idx(x_ + 1, y_)].type:
            checks[self._idx(x_, y_)] = 1
            checks[self._idx(x_ - 1, y_)] = 1
            checks[self._idx(x_ + 1, y_)] = 1
            is_del = True
        if d00.type == self.data[self._idx(x_, y_ - 1)].type and d00.type == self.data[self._idx(x_, y_ + 1)].type:
            checks[self._idx(x_, y_)] = 1
            checks[self._idx(x_, y_ - 1)] = 1
            checks[self._idx(x_, y_ + 1)] = 1
            is_del = True
        if self.game_type == self.GT_HEXA:
            if d00.type == self.data[self._idx(x_ - 1, y_ - 1)].type and d00.type == self.data[self._idx(x_ + 1, y_ + 1)].type:
                checks[self._idx(x_, y_)] = 1
                checks[self._idx(x_ - 1, y_ - 1)] = 1
                checks[self._idx(x_ + 1, y_ + 1)] = 1
                is_del = True
            if d00.type == self.data[self._idx(x_ - 1, y_ + 1)].type and d00.type == self.data[self._idx(x_ + 1, y_ - 1)].type:
                checks[self._idx(x_, y_)] = 1
                checks[self._idx(x_ - 1, y_ + 1)] = 1
                checks[self._idx(x_ + 1, y_ - 1)] = 1
                is_del = True

        return checks[:], is_del

    def check_match(self):
        checks = []
        for i in range(self.width * self.height): checks.append(0)
        if self.game_type == self.GT_TETRIS:
            y = self.height - 2
            while y > 0:
                checks, is_del = self._check_line(checks, y)
                y -= 1

        elif self.game_type in (self.GT_HEXA, self.GT_MATCH):
            y = 1
            while y < self.height - 1:
                x = 1
                while x < self.width - 1:
                    checks, is_del = self._check_match3(checks, x, y)
                    x += 1
                y += 1
        del_cnt = self._delete_checks(checks)
        return del_cnt, del_cnt // 2

    def check_select(self, cam, xx, yy):
        # {
        # // Space for selection buffer
        iarray = ctypes.c_int * 64
        selectBuff = iarray(0, )

        # // Hit counter and viewport storeage
        # GLint hits, viewport[4];

        # // Setup selection buffer
        glSelectBuffer(64, selectBuff)

        # // Get the viewport
        viewport = glGetIntegerv(GL_VIEWPORT)
        # print(viewport)
        # // Switch to projection and save the matrix
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()

        # // Change render mode
        glRenderMode(GL_SELECT)

        # // Establish new clipping volume to be unit cube around
        # // mouse cursor point (xPos, yPos) and extending two pixels
        # // in the vertical and horzontal direction. Remember OpenGL specifies the
        # // y coordinate from the bottom, Windows from the top. So windows position
        # // (as measured from the top) subtract the height and you get it in terms
        # // OpenGL Likes.
        glLoadIdentity()
        gluPickMatrix(xx, viewport[3] - yy + viewport[1], 2, 2, viewport)

        # // Apply perspective matrix
        fAspect = viewport[2] / viewport[3]
        gluPerspective(45.0, fAspect, 1.0, 425.0)
        cam.look()
        # // Draw the scene
        self.render(use_name=True)

        # // Collect the hits
        hits = glRenderMode(GL_RENDER)

        # // If a single hit occured, display the info.
        # if hits == 1:
        #     for i in range(64):
        #         print(selectBuff[i], end=',')
        #     print('')
        #     ProcessPlanet(selectBuff)
        for i in range(64):
            print(selectBuff[i], end=',')
        print('')
        if selectBuff[0] > 0: sel = selectBuff[3]
        else: sel = None
        del selectBuff
        # // Restore the projection matrix
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()

        # // Go back to modelview for normal rendering
        glMatrixMode(GL_MODELVIEW)
        return sel
        # }

    def update(self, ms):
        # for gc in self.data:
        # try:
        #         if gc.type > 0:
        #             tex_cnt = len(GameCell.tex[gc.type].keys())
        #             gc.animate += ms
        #             if gc.animate > 1.0:
        #                 gc.tex_index += 1
        #                 gc.animate -= 1.0
        #             _, gc.tex_index = divmod(gc.tex_index, tex_cnt)
        #             _, gc.rot.x = divmod(gc.rot.x + ms * 10.0, 360)
        #             _, gc.rot.y = divmod(gc.rot.y + ms * 10.0, 360)
        #             _, gc.rot.z = divmod(gc.rot.z + ms * 10.0, 360)
        #     except KeyError:
        #         continue
        self.ec.update(ms)

    def swap(self, idx1, idx2):
        if len(self.data) > idx1 and len(self.data) > idx2:
            temp = self.data[idx1]
            self.data[idx1] = self.data[idx2]
            self.data[idx2] = temp

    def render(self, shader=None, use_name=False):
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glInitNames()
        glPushName(0)
        for y in range(self.height):
            for x in range(self.width):
                idx = self._idx(x, y)
                gc = self.data[idx]
                if gc.type > 0:
                    if gc.type in GameCell.tex.keys():
                        glColor4f(1.0, 1.0, 1.0, 1.0)
                        glEnable(GL_TEXTURE_2D)
                        try:
                            tid, alpha = GameCell.tex[gc.type][gc.tex_index]
                            if shader is not None: shader.pass_texture(tid)
                            if GameCell.use_multi_tex > 1:
                                tid2, _ = GameCell.tex[1][0]
                                if shader is not None: shader.pass_texture(tid2, number=2)
                                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)
                                '''
                                glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE)
                                glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0)
                                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR)
                                glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1)
                                glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR)
                                '''
                                glActiveTexture(GL_TEXTURE0)
                                glBindTexture(GL_TEXTURE_2D, tid2)
                                glActiveTexture(GL_TEXTURE1)

                            if alpha: glEnable(GL_BLEND)
                            else: glDisable(GL_BLEND)
                            glBindTexture(GL_TEXTURE_2D, tid)
                        except KeyError:
                            continue
                    else:
                        glDisable(GL_TEXTURE_2D)
                        glColor4fv(RGBA.Colors[gc.type])

                    if gc.type < 20:
                        if GameCell.use_multi_tex > 1:
                            self.do.glDrawCubeMT(x, 0, y, 0.45, rotate_x=gc.rot.x, rotate_y=gc.rot.y, rotate_z=gc.rot.z,
                                                 sel_name=idx)
                        else:
                            self.do.glDrawCube(x, 0, y, 0.45, rotate_x=gc.rot.x, rotate_y=gc.rot.y, rotate_z=gc.rot.z,
                                               sel_name=idx)
                    else:
                        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
                        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
                        self.do.gluDrawSphere(x, 0, y, 0.45, slices=16, stacks=16, rotate_x=gc.rot.x, rotate_y=gc.rot.y,
                                              rotate_z=gc.rot.z, sel_name=idx)
        glPopMatrix()
        glLoadName(10000)
        self.ec.render(shader)

    '''
    def gen_display_data(self):
        self.vert_data = array.array('f', [])
        self.norm_data = array.array('f', [])
        self.tex_data = array.array('f', [])
        self.vert_count = 0

        for y in range(self.height):
            for x in range(self.width):
                gc = self.data[x + y * self.width]
                if gc.type > 10:
                    self.vert_count += 24
                    self.vert_data += gc.vert
                    self.tex_data += gc.tex
                    self.norm_data += gc.norm

    def render(self):
        self.gen_display_data()
        glEnableClientState(GL_VERTEX_ARRAY)  # // Enable Vertex Arrays
        glEnableClientState(GL_NORMAL_ARRAY)  # // Enable Normal Arrays
        glEnableClientState(GL_TEXTURE_COORD_ARRAY)  # // Enable Texture Coord Arrays
        # // Set The Vertex Pointer To Our Normal Data
        glNormalPointer(GL_FLOAT, 0, self.norm_data.tostring())
        # // Set The Vertex Pointer To Our TexCoord Data
        glTexCoordPointer(2, GL_FLOAT, 0, self.tex_data.tostring())
        glVertexPointer(3, GL_FLOAT, 0, self.vert_data.tostring())
        glDrawArrays(GL_QUADS, 0, self.vert_count)
        glDisableClientState(GL_VERTEX_ARRAY)  # // Disable Vertex Arrays
        glDisableClientState(GL_NORMAL_ARRAY)  # // Disable Normal Arrays
        glDisableClientState(GL_TEXTURE_COORD_ARRAY)  # // Disable Texture Coord Arrays
    '''
